﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web.Mvc;
using System.Text.RegularExpressions;

namespace CodeTunnel.MvcUtilities.Utilities
{
    /// <summary>
    /// A library of common static utilities.
    /// </summary>
    public static class CommonUtils
    {
        /// <summary>
        /// Transforms a string into a human-readable, URL friendly string.
        /// </summary>
        /// <param name="text">The text to be transformed.</param>
        /// <returns>string</returns>
        public static string CreateFriendlyUrl(string text)
        {
            text = (text ?? "").Trim().ToLower();
            StringBuilder url = new StringBuilder();
            foreach (char ch in text)
            {
                switch (ch)
                {
                    case ' ':
                        url.Append('-');
                        break;
                    case '&':
                        url.Append("and");
                        break;
                    case '\'':
                        break;
                    default:
                        if ((ch >= '0' && ch <= '9') ||
                            (ch >= 'a' && ch <= 'z'))
                        {
                            url.Append(ch);
                        }
                        break;
                }
            }
            return url.ToString();
        }

        /// <summary>
        /// Builds and renders a View or Partial View to a string.
        /// </summary>
        /// <param name="controller">The current controller.</param>
        /// <param name="viewName">The name of the View to be rendered.</param>
        /// <param name="model">The object model to be passed to the View.</param>
        /// <param name="isPartial">Is this a Partial View?</param>
        /// <returns></returns>
        public static string RenderViewToString(Controller controller, string viewName, object model, bool isPartial)
        {
            controller.ViewData.Model = model;
            try
            {
                using (StringWriter sw = new StringWriter())
                {
                    ViewEngineResult viewResult = isPartial ? ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName) : ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null);
                    ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                    viewResult.View.Render(viewContext, sw);

                    return sw.GetStringBuilder().ToString();
                }
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }

        #region -= HTML Sanitize =-

        /// <summary>
        /// All HTML tags regular expression.
        /// </summary>
        private static Regex _tags = new Regex("<[^>]*(>|$)",
    RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);

        /// <summary>
        /// All allowed HTML tags regular expression.
        /// </summary>
        private static Regex _whitelist = new Regex(@"
    ^</?(b(lockquote)?|code|d(d|t|l|el)|em|h(1|2|3)|i|kbd|li|ol|p(re)?|s(ub|up|trong|trike)?|ul)>$|
    ^<(b|h)r\s?/?>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);

        /// <summary>
        /// Allowed HTML attributes for the 'a' tag.
        /// </summary>
        private static Regex _whitelist_a = new Regex(@"
    ^<a\s
    href=""(\#\d+|(https?|ftp)://[-a-z0-9+&@#/%?=~_|!:,.;\(\)]+)""
    (\stitle=""[^""<>]+"")?\s?>$|
    ^</a>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);

        /// <summary>
        /// Allowed HTML attributes for the 'img' tag.
        /// </summary>
        private static Regex _whitelist_img = new Regex(@"
    ^<img\s
    src=""https?://[-a-z0-9+&@#/%?=~_|!:,.;\(\)]+""
    (\swidth=""\d{1,3}"")?
    (\sheight=""\d{1,3}"")?
    (\salt=""[^""<>]*"")?
    (\stitle=""[^""<>]*"")?
    \s?/?>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);


        /// <summary>
        /// Sanitize any potentially dangerous tags from the provided raw HTML input using
        /// a whitelist based approach, leaving the "safe" HTML tags
        /// </summary>
        /// <param name="html">HTML to be sanitized.</param>
        /// <returns>string</returns>
        public static string Sanitize(string html)
        {
            if (String.IsNullOrEmpty(html)) return html;

            string tagname;
            Match tag;

            // match every HTML tag in the input
            MatchCollection tags = _tags.Matches(html);
            for (int i = tags.Count - 1; i > -1; i--)
            {
                tag = tags[i];
                tagname = tag.Value.ToLowerInvariant();

                if (!(_whitelist.IsMatch(tagname) || _whitelist_a.IsMatch(tagname) || _whitelist_img.IsMatch(tagname)))
                {
                    html = html.Remove(tag.Index, tag.Length);
                    System.Diagnostics.Debug.WriteLine("tag sanitized: " + tagname);
                }
            }

            return html;
        }

        #endregion
    }
}
